
#ifndef __OBJTYPES_H
#define __OBJTYPES_H

#define TAG_AS_PTR(x) (void *) ((int) x | TAG_PTR)
#define REMOVE_TAG(x) (void *) ((int) x & 0xfffffffc)
#define UNTAG(x) ((yjk_object) (void *) ((int) x & 0xfffffffc))
#define MASK(x) (((int) x) & 0x3)
#define OBJ_HDR(x) ((yjk_obj_header *) x)

//Basic tags
#define TAG_INT    0x0 //30 bit signed integer
#define TAG_IMM    0x2 //Other immediate
#define TAG_PTR    0x1
#define TAG_OTHER2 0x3

//Types
#define TYPE_NONE    0x0
#define TYPE_PTR     0x1
#define TYPE_IMM     0x2
#define TYPE_OTHER2  0x3
//The order of the following types is important
#define TYPE_FIXNUM  0x3
#define TYPE_BIGINT  0x4
#define TYPE_RATIO   0x5
#define TYPE_COMPLEX 0x6
#define TYPE_FLOAT   0x7
#define TYPE_COMPLEX_INEXACT 0x8

#define TYPE_STRING  0x9
#define TYPE_STRUCT  0xa

//Other immediate types
#define TYPE_FALSE   0x10
#define TYPE_TRUE    0x11

#define IMM_TRUE  ((void *) (((unsigned int) TYPE_TRUE  << 2) | TAG_IMM))
#define IMM_FALSE ((void *) (((unsigned int) TYPE_FALSE << 2) | TAG_IMM))

#define IMM_TYPE(x) (((unsigned int) x >> 2) & 0x3f)


typedef struct 
{
  unsigned int tag : 1   __attribute__((packed));
  unsigned int free : 1  __attribute__((packed));
  unsigned int type : 6  __attribute__((packed)); //type
  unsigned int size : 24 __attribute__((packed)); //size in bytes
  char data[];
} yjk_obj_header;

//simplifies checking and setting tags
struct yjk_tagged
{
  unsigned int tag : 2    __attribute__((packed));
  unsigned int value : 30 __attribute__((packed));
};


struct yjk_fixnum
{
  unsigned int tag : 2  __attribute__((packed));
  int value        : 30 __attribute__((packed));
};

struct yjk_other_imm
{
  unsigned int tag : 2   __attribute__((packed));
  unsigned int type : 6  __attribute__((packed));
  unsigned int data : 24 __attribute__((packed));
};

union yjk_object
{
  struct yjk_tagged    tagged;
  struct yjk_fixnum    fixnum;
  struct yjk_other_imm other_imm;
  struct yjk_bigint    *bigint;
  struct yjk_ratio     *ratio;
  struct yjk_complex   *complex;
  struct yjk_float     *flt;
  struct yjk_string    *string;
  yjk_obj_header    *object;
  void          *pointer;
};


//Object types
struct yjk_ratio
{
  yjk_obj_header header __attribute__((packed));
  union yjk_object numerator   __attribute__((packed));
  union yjk_object denominator __attribute__((packed));
};

struct yjk_complex
{
  yjk_obj_header header __attribute__((packed));
  union yjk_object real   __attribute__((packed));
  union yjk_object imag   __attribute__((packed));
};

struct yjk_bigint
{
  yjk_obj_header header __attribute__((packed));
  uint32_t length   __attribute__((packed));
  int32_t data[];
};

struct yjk_float
{
  yjk_obj_header header  __attribute__((packed));
  double value       __attribute__((packed));
};

struct yjk_string
{
  yjk_obj_header header  __attribute__((packed));
  char data[]        __attribute__((packed));
};

typedef union yjk_object  YJK_OBJECT;
typedef struct yjk_tagged    YJK_TAGGED;
typedef struct yjk_fixnum    YJK_FIXNUM;
typedef struct yjk_other_imm YJK_OTHER_IMM;
typedef struct yjk_ratio   YJK_RATIO;
typedef struct yjk_complex YJK_COMPLEX;
typedef struct yjk_bigint  YJK_BIGINT;
typedef struct yjk_float   YJK_FLOAT;
typedef struct yjk_string  YJK_STRING;


int
get_type(void *);

yjk_obj_header *
to_float(yjk_obj_header *);



#endif
